#pragma once

#include "Log.h"
#include "Common.h"

#include "Connection.h"
#include "Intaddr.h"
#include <string>
#include <sys/epoll.h>
#include "Reactor.h" // 回指指针要被使用了,Channel要看见Reactor

namespace zmh
{
    class Channel : public Connection
    {
    public:
        Channel(int sockfd, const Intaddr &addr)
            : _sockfd(sockfd), _addr(addr)
        {
            // 设置关心事件---读事件关心 + ET模式
            SetEvents(EPOLLIN | EPOLLET);
            // 将_linstensock对应的fd设置为非阻塞
            SetFdNonBlock(_sockfd);
        }

        virtual void Recv()
        {
            while (true)
            {
                char buffer[1024];
                ssize_t n = recv(_sockfd, buffer, sizeof buffer, 0);
                if (n > 0)
                {
                    buffer[n] = 0;
                    // if (buffer[n - 1] == '\n')
                    //     buffer[n - 1] = 0;
                    // else
                    //     buffer[n] = 0;
                    _inbuffer += buffer;
                }
                else if (n == 0) // 对端关闭连接
                {
                    LOG(LogLevel::DEBUG) << "Begin";
                    Except();
                    LOG(LogLevel::DEBUG) << "Eend:";
                    return;
                }
                else
                {
                    if (errno == EAGAIN || errno == EWOULDBLOCK) // 无数据
                        break;
                    else if (errno == EINTR) // 信号中断
                        continue;
                    else // 错误发生
                    {
                        Except();
                        return;
                    }
                }
            }
            // 数据处理
            _outbuffer = _inbuffer; // 目前暂时回显_inbuffer内容
            _inbuffer.clear();
            LOG(LogLevel::DEBUG) << "_inbuffer:\n"
                                 << _inbuffer;
            LOG(LogLevel::DEBUG) << "_outbuffer:\n"
                                 << _outbuffer;
            // 发送数据
            Send();
        }
        virtual void Send()
        {
            while (true)
            {
                ssize_t n = send(_sockfd, _outbuffer.c_str(), _outbuffer.size(), 0);
                if (n >= 0)
                {
                    _outbuffer.erase(0, n);
                    if (_outbuffer.empty())
                        break;
                }
                else
                {
                    if (errno == EAGAIN || errno == EWOULDBLOCK) // 缓冲区已满
                    {
                        // 对_sockfd对应连接增添写事件关心
                        Owner()->ModConnection(_sockfd, EPOLLIN | EPOLLOUT | EPOLLET);
                        break;
                    }
                    else if (errno == EINTR) // 信号中断
                        continue;
                    else // 错误发生
                    {
                        Except();
                        return;
                    }
                }
            }
        }
        virtual void Except()
        {
            // 1.获取有问题的fd
            int fd = GetFd();
            // 2.从管理者中移除该连接
            Owner()->DelConnection(fd);
        }
        virtual int GetFd() { return _sockfd; }

    private:
        int _sockfd;
        Intaddr _addr;
        std::string _inbuffer;
        std::string _outbuffer;
    };
}